
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>延迟消息的设置方法 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>延迟消息的设置方法 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">RocketMQ中的延迟消息是什么？它和定时消息有什么区别？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">延迟消息是指生产者发送消息后，消费者不会立即收到，而是在指定的时间后才能消费到该消息。在RocketMQ中，延迟消息和定时消息是同一种机制，只是表述角度不同：延迟消息强调的是从发送到可消费之间存在一个延迟时间，而定时消息强调的是消息将在未来某个确定的时间点被投递。</div>
          </div>
          <div class="card-source">来源: 延迟消息基本概念, 延迟消息与定时消息的关系</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">应用</div>
          <div class="card-question">请列举至少三个延迟消息的典型应用场景。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">应用</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. 订单超时关闭：创建订单时发送延迟消息，到期后检查订单状态，如未支付则自动关闭。 2. 支付结果检查：支付请求发出后发送延迟消息，延迟一定时间后查询第三方支付系统以确认最终支付状态。 3. 预约系统提醒：用户预约服务后发送延迟消息，在预约时间前固定时间触发提醒。</div>
          </div>
          <div class="card-source">来源: 典型应用场景</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">RocketMQ是否支持任意时间的延迟？它内部是如何处理不同延迟时间的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">不支持。RocketMQ不支持任意时间精度的延迟，而是使用固定的延迟等级机制。默认提供18个延迟等级，每个等级对应一个固定的延迟时间（例如：1级对应1秒，2级对应5秒，以此类推）。</div>
          </div>
          <div class="card-source">来源: RocketMQ的延迟等级机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">原理</div>
          <div class="card-question">当生产者发送一个延迟消息时，Broker内部会执行哪些关键步骤来处理它？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">原理</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Broker接收到消息后，首先识别出它是延迟消息，然后会修改消息的Topic为内部主题`SCHEDULE_TOPIC_XXXX`，同时将原始的Topic和队列信息保存在消息的属性中。最后，根据消息设置的延迟等级，将其分配到`SCHEDULE_TOPIC_XXXX`主题下对应的队列中进行存储。</div>
          </div>
          <div class="card-source">来源: 详细实现流程 - 消息发送阶段</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">原理</div>
          <div class="card-question">描述RocketMQ中延迟消息从“到期”到被消费者“消费”的完整投递流程。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">原理</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">一个名为`ScheduleMessageService`的定时服务会定时扫描各个延迟队列。当它发现有消息到达预设的延迟时间点后，会重新构建该消息，恢复其原始的Topic和队列信息。然后，将这个恢复后的消息立即投递到原始的Topic中。这样，消费者就可以像消费普通消息一样从原始Topic消费该消息，整个延迟过程对消费者是透明的。</div>
          </div>
          <div class="card-source">来源: 详细实现流程 - 定时检查阶段与消息投递阶段</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">如果默认的18个延迟等级不满足业务需求，可以如何进行自定义？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以通过修改Broker的配置文件（例如 broker.conf），在其中配置`messageDelayLevel`参数来自定义延迟等级。例如：`messageDelayLevel=1s 5s 10s ... 3h 4h`。需要注意的是，此修改需要在Broker启动前配置，并且会影响所有使用该Broker的延迟消息。</div>
          </div>
          <div class="card-source">来源: 自定义延迟等级</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">限制</div>
          <div class="card-question">RocketMQ延迟消息在使用上有哪些主要的限制？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">限制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主要限制包括：1. 延迟精度有限，只支持预设的延迟等级，不支持精确时间点；2. 默认有最大延迟时间限制（2小时）；3. 不支持严格的顺序消息，不同延迟等级的消息投递顺序无法保证；4. Broker重启可能导致短时间的延迟投递不准确。</div>
          </div>
          <div class="card-source">来源: 使用限制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">架构</div>
          <div class="card-question">实现RocketMQ延迟消息功能的核心组件是哪两个？它们各自的作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">架构</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">核心组件是：1. 延迟队列(SCHEDULE_TOPIC_XXXX)，其作用是临时存储所有被发送的延迟消息；2. 定时检查服务(ScheduleMessageService)，其作用是周期性地检查延迟队列中的消息是否到期，并将到期的消息取出、恢复并投递到原始的Topic中。</div>
          </div>
          <div class="card-source">来源: 整体架构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">实践</div>
          <div class="card-question">针对延迟消息的可靠性，文档中提到了哪些最佳实践？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">实践</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">最佳实践包括：1. 对关键业务的延迟消息应考虑实现额外的确认机制；2. 消费端需要实现幂等处理，以避免因系统重试或延迟不准等问题导致的重复消费；3. 对于非常关键的业务，可以实现备份触发机制，例如使用数据库定时任务作为兜底方案。</div>
          </div>
          <div class="card-source">来源: 最佳实践</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
